/*********************************************************************************
 *      Copyright:  (C) 2021 iot
 *                  All rights reserved.
 *
 *       Filename:  hal.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0
 *         Author:  mk
 *                 
 ********************************************************************************/


#include "hal.h"
#include "tsl2561.h"
#include "../lib//logger.h"

#define RIP_GPIONAME        "gpiochip0"

static struct gpiod_chip        *s_chip;
static struct gpiod_line        *s_light_lines[LIGHT_MAX];  /*relay GPIO lines*/
static struct gpiod_line        *s_infrared_lines;  /* infrared GPIO lines*/ 
static struct gpiod_line_event  event;
static int                      s_light_cnt;

int hal_init(light_ctx_t *ctx)
{
    int         i;
    
    if(!ctx)
    {
        log_err("error: input ctx failure!\n");
        return -1;
    }
    
    /*  current configure light counts */ 
    s_light_cnt=ctx->light_cnt;

    /*  gpiod open chip  */
    s_chip=gpiod_chip_open_by_name(RIP_GPIONAME);
    if (!s_chip) 
    {
        log_err("gpiod open chip failure, maybe you need running as root!\n");
        return -2;
    }
    log_nrml("Successful initialization of the chip!\n");

    /*  gpiod get gpio lines and request relay pin as output  */
    for(i=0; i<ctx->light_cnt; i++)
    {
        s_light_lines[i]=gpiod_chip_get_line(s_chip, ctx->light_pins[i]);
        if( !s_light_lines[i] )
        {
            log_err("gpiod get line for pin[%d] failure\n", ctx->light_pins[i]);
            return -3;
        }
        gpiod_line_request_output(s_light_lines[i], "lightd", 0);
    }
    log_nrml("GPIO line successfully applied and set to output!\n");


    if( tsl2561_init()< 0 )
    {
        log_err("LUX sensor TSL2561 initialise failure\n");
        return -2;
    }

    /*  gpiod get gpio lines and request infrared pin as input  */
    if( ctx->infrared_pin )
    {
        s_infrared_lines = gpiod_chip_get_line(s_chip, ctx->infrared_pin);
        gpiod_line_request_rising_edge_events(s_infrared_lines, "infrared");
        log_nrml("infrared GPIO input lines request for rising edge event successfully!\n");
    }



    return 0;
}


void turn_light(int gpio_line, int on_off)
{
    if( gpio_line >= s_light_cnt)
    {
        log_err("light[%d] not support in configure file!\n", gpio_line);
        return ;
    }
    
    if( OFF == on_off)
    {
        gpiod_line_set_value(s_light_lines[gpio_line], 0); 
    }
    else
    {
        gpiod_line_set_value(s_light_lines[gpio_line], 1);   
    }

    return ;
}

void hal_term(light_ctx_t *ctx)
{
    int             i;

    if(!ctx)
    {
        log_err("Invalid input arguments\n");
        return ;
    }

    for(i=0; i<ctx->light_cnt; i++)
    {
        gpiod_line_release(s_light_lines[i]);
    }

    gpiod_line_release(s_infrared_lines);

    gpiod_chip_close(s_chip);

    return ;
}

/*  Return value: 1(HIGH): Sombody detected  0(LOW): Nobody detected  */
int infrared_detect(void)
{

    /*  This function will block, must call it to setup */
    if( gpiod_line_event_wait(s_infrared_lines, NULL) < 0 )
    {
        log_err("infrared gpiod line wait event failure!\n");
        return 0;
    }

    /*  This function will block, must read to clear the event  */
    if (gpiod_line_event_read(s_infrared_lines, &event) < 0)
    {
        log_err("gpiod line event read failure!\n");
        return 0;
    }

    if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
        return 1;
    else
        return 0;


}

